//-WinterFramework ? WinterFeather
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Threading.Tasks;
using System.Linq;
public class SaveDataManager : SingleMono<SaveDataManager>
{
    public Dictionary<SaveDataTag, SaveCondition> SaveCondition;
    Dictionary<SaveDataTag, Func<Task>> SaveAction;
    string savePath;

    List<KeyValuePair<SaveDataTag, SaveCondition>> SaveConditionList;

    object saveLocker = new object();

    public void Init()
    {
        InitPath();
        InitSaveAction();
    }
    void InitPath()
    {
        savePath = Path.Combine(Application.persistentDataPath, "SaveData");
        Debug.Log(savePath);
        if (!Directory.Exists(savePath))
        {
            Directory.CreateDirectory(savePath);
        }
    }
    void InitSaveAction()
    {
        SaveCondition = new Dictionary<SaveDataTag, SaveCondition>();
        SaveAction = new Dictionary<SaveDataTag, Func<Task>>();
        SaveConditionList = new List<KeyValuePair<SaveDataTag, SaveCondition>>();
    }

    public T LoadAndInitData<T>(T data, SaveDataTag tag) where T : ISaveable<T>, new()
    {
        data = LoadDataBinary<T>(tag.ToString()).Result;
        if (data == null)
        {
            data = new T();
            data.Init(tag);
        }
        InitSaveData(tag, data);
        return data;
    }

    void InitSaveData<T>(SaveDataTag tag, ISaveable<T> data)
    {
        SaveCondition.Add(tag, new SaveCondition());
        SaveCondition[tag].isNeedSave = true;
        SaveAction.Add(tag, data.Save);
        SaveConditionList = SaveCondition.ToList();
    }

    private new void Awake()
    {
        base.Awake();
        Init();
    }
    async void Update()
    {
        for (int i = 0; i < SaveConditionList.Count; i++)
        {
            if (SaveConditionList[i].Value.isNeedSave)
            {
                SaveCondition[SaveConditionList[i].Key].isNeedSave = false;
                await SaveAction[SaveConditionList[i].Key].Invoke();
            }
        }
    }
    public Task SaveDataBinary<T>(string key, T data) 
    {
        return Task.Run(
        () =>
        {
            lock (saveLocker)
            {
                byte[] buff = BinarySerializationHelper.SerializeToBinary(data);
                File.WriteAllBytes(Path.Combine(savePath, key), buff);
            }
        }
        );
    }
    public Task<T> LoadDataBinary<T>(string key) 
    {
        lock (saveLocker)
        {
            if (File.Exists(Path.Combine(savePath, key)))
            {
                byte[] buff = File.ReadAllBytes(Path.Combine(savePath, key));
                T data = BinarySerializationHelper.DeserializeFromBinary<T>(buff);
                return Task.FromResult<T>(data);
            }
            else
            {
                return Task.FromResult<T>( default(T)); 
            }
        }
    }
}

public class SaveCondition
{
    public bool isNeedSave;
}
public enum SaveDataTag
{
    SaveStyle1, SaveStyle2, SaveStyle3
}

[Serializable]
public class SaveData1 : ISaveable<SaveData1>
{
    public int count;
    public List<int> ints;
    public string SaveName => saveName;
    string saveName;
    public SaveDataTag SaveTag => saveTag;
    public SaveDataTag saveTag;
    public void Init(SaveDataTag tag)
    {
        ints = new List<int>();
        this.saveTag = tag;
        saveName = saveTag.ToString();
    }

    public Task Save()
    {
        Debug.Log(count);
        count++;
        return SaveDataManager.Instance.SaveDataBinary(saveName, this);
    }
}

[Serializable]
public class SaveData2 :  ISaveable<SaveData2>
{
    public int id;
    public List<int> ints;
    public string SaveName => saveName;
    string saveName;
    public SaveDataTag SaveTag => saveTag;
    public SaveDataTag saveTag;

    public void Init(SaveDataTag tag)
    {
        ints = new List<int>();
        this.saveTag = tag;
        saveName = saveTag.ToString();
    }

    public  Task Save()
    {
        Debug.Log(saveName);
        ints.Add(ints.Count);
        Debug.Log(ints.Count);
        return SaveDataManager.Instance.SaveDataBinary(saveName, this);
    }
}


public interface ISaveable<T>
{
    public void Init(SaveDataTag tag);
    public Task Save();
    public string SaveName { get; }
    public SaveDataTag SaveTag{ get; }
}


